package com.xishu.task;

import com.xishu.client.CustomerEmailClient;
import com.xishu.config.Config;
import com.xishu.config.Constant;
import com.xishu.entity.Company;
import com.xishu.entity.customer.*;
import com.xishu.service.*;
import com.xishu.util.DateUtil;
import com.xishu.util.Tools;
import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static com.xishu.config.Constant.CUSTOMER_TASK_TYPE_RE_NEW_VIP;

/**
 * 会员系统的后台任务
 * <p>
 * 包含会员等级优惠券的发送
 * <p>
 * 生日邮件优惠券发送
 * <p>
 * 营销的短信、邮件，优惠券发送
 */
@Component
public class CustomerSystemTask implements Tools {
    private static Logger logger = LoggerFactory.getLogger(CustomerSystemTask.class);
    private CommonService commonService = CommonService.getInstance();
    private CustomerService customerService = CustomerService.getInstance();
    private CustomerTaskService customerTaskService = CustomerTaskService.getInstance();
    private Config config = Config.getInstance();

    /**
     * 每30分钟定时执行一次
     * <p>
     * 一分钟后再校验
     *
     * @throws Exception
     */
    @Scheduled(initialDelay = 60 * 1000, fixedDelay = 30 * 60 * 1000)
    public void action() throws Exception {
        if (config.isWindows()) {
            return;
        }

        LeaderService leaderService = LeaderService.getInstance();
        if (!leaderService.elect()) {
            logger.info("elect failed");
            return;
        }

        ThreadContext.put(Constant.REQUEST_ID, "customer system task");
        logger.info("will do the CustomerSystemTask");

        vipRenewNoticeTask();
        birthdayTicketTask();
        marketTask();
    }


    /**
     * 生日邮件任务处理
     */
    private void birthdayTicketTask() {
        try {
            logger.info("birthdayTicketTask");

            CustomerTaskService customerTaskService = CustomerTaskService.getInstance();
            commonService.doAll(new Company(), (c) -> {
                try {
                    logger.info("check the company {}", c.getId());
                    customerTaskService.dealCompanyBirthDayTicket(c);
                } catch (Exception e) {
                    logger.error("e", e);
                }
            });
        } catch (Exception e) {
            logger.error("e", e);
        }
    }

    /**
     * 营销任务的处理
     */
    private void marketTask() {
        try {
            logger.info("marketTask");

            commonService.doAll(new MarketTask(), (task) -> {
                logger.info("action the market task {}", task.getId());

                //如果是冻结的任务不执行
                if (getInt(task.getStatus()) != Constant.MARKET_TASK_STATUS_ONLINE) {
                    logger.info("task {} is frozen");
                    return;
                }

                //如果是一次性任务，并且是立即执行的，也不执行
                PeriodTimeConfig periodTimeConfig = task.getPeriodTimeConfig();

                if (getBoolean(periodTimeConfig.getNowTime())) {
                    logger.info("it is now time task");
                    return;
                }

                //判断任务的执行时间
                int hour = getInt(periodTimeConfig.getHour());
                int currentHour = DateUtil.getHour(System.currentTimeMillis());
                if (hour != currentHour) {
                    logger.info("hour not match");
                    return;
                }

                //如果是一次性任务，并且已经执行过了，也不执行
                if (getBoolean(periodTimeConfig.getOnce())) {
                    MarketHistory marketHistory = new MarketHistory();
                    marketHistory.setTaskId(task.getId());
                    Optional<MarketHistory> marketHistoryOptional = commonService.searchOneOptional(marketHistory);
                    if (marketHistoryOptional.isPresent()) {
                        logger.info("the history {} task executed", task.getId());
                        return;
                    }

                    //没有执行过，那么看下时间是否到了
                    Long onceExecuteTime = periodTimeConfig.getOnceExecuteTime();
                    String executeDate = DateUtil.formatDayDate(onceExecuteTime);
                    String today = DateUtil.formatDayDate(System.currentTimeMillis());

                    //时间不相等，那么不执行
                    if (!equals(today, executeDate)) {
                        logger.info("not the execute time {}", executeDate);
                        return;
                    }

                    //开始一次性任务执行
                    try {
                        customerService.executeMarketTask(task);
                    } catch (Exception e) {
                        logger.error("e", e);
                    }
                } else {
                    //周期性任务，判断是否到达了该周期
                    boolean canAction = customerTaskService.canAction(task.getPeriodTimeConfig(), System.currentTimeMillis());

                    if (canAction) {
                        try {
                            customerService.executeMarketTask(task);
                        } catch (Exception e) {
                            logger.error("e", e);
                        }
                    }
                }
            });
        } catch (Exception e) {
            logger.error("e", e);
        }
    }

    /**
     * 续费VIP邮件
     */
    public void vipRenewNoticeTask() {
        try {
            logger.info("vipRenewNoticeTask");
            long currentTimeMillis = System.currentTimeMillis();
            //当天的结束时间
            long endTimeToday = DateUtil.endTimeInDay(currentTimeMillis);

            commonService.doAll(new VipRenewMode(), (vipRenewMode -> {
                logger.info("action for vip renew mode {} and company Id {}", vipRenewMode.getId(), vipRenewMode.getCompanyId());

                //不做提醒
                if (!getBoolean(vipRenewMode.getRemind())) {
                    logger.info("do not remind for company {}", vipRenewMode.getCompanyId());
                    return;
                }

                Long companyId = vipRenewMode.getCompanyId();
                Company company = getCompany(companyId);
                if (company == null) {
                    logger.info("can not find the company {}", companyId);
                    return;
                }

                VipRenewEmailTemplate vipRenewEmailTemplateQuery = new VipRenewEmailTemplate();
                vipRenewEmailTemplateQuery.setCompanyId(vipRenewMode.getCompanyId());
                Optional<VipRenewEmailTemplate> vipRenewEmailTemplateOptional = commonService.searchOneOptional(vipRenewEmailTemplateQuery);

                //还没有配置提供模板
                if (!vipRenewEmailTemplateOptional.isPresent()) {
                    logger.info("can not find the renew email template");
                    return;
                }

                VipRenewEmailTemplate vipRenewEmailTemplate = vipRenewEmailTemplateOptional.get();

                //提供时间问题
                if (vipRenewEmailTemplate.getRemindDay() == null || vipRenewEmailTemplate.getRemindDay() < 0) {
                    logger.info("remind day is {}", vipRenewEmailTemplate.getRemindDay());
                    return;
                }

                //内容或者标题有问题也不发
                if (isEmpty(vipRenewEmailTemplate.getTitle()) || isEmpty(vipRenewEmailTemplate.getContent())) {
                    logger.info("vip title or content empty");
                    return;
                }

                //查看是否在指定的时间范围内
                Integer hour = getInt(vipRenewEmailTemplate.getHour());
                int currentHour = DateUtil.getHour(System.currentTimeMillis());
                if (hour != currentHour) {
                    logger.info("not the execute hour");
                    return;
                }

                Customer customerQuery = new Customer();
                customerQuery.setCompanyId(companyId);
                Quota quota = getQuota(companyId);
                if (quota == null) {
                    logger.info("the company can not has quota");
                    return;
                }

                //记录发送了多少条，然后写操作日志
                MarketHistory marketHistory = new MarketHistory();
                marketHistory.setCompanyId(companyId);
                marketHistory.setTaskName_zh(Config.getInstance().vip_renew_task_name_zh());
                marketHistory.setTaskName_en(Config.getInstance().vip_renew_task_name_en());

                commonService.doAll(customerQuery, (customer -> {
                    //不是VIP，不做通知
                    if (!getBoolean(customer.getVip())) {
                        logger.info("customer {} not the vip ", customer.getId());
                        return;
                    }

                    //没有到期的，也不做提醒
                    Long vipEndTime = getLong(customer.getVipEndTime());
                    //已经超了
                    if (vipEndTime < currentTimeMillis) {
                        logger.info("{} vip end time great than current time", customer.getId());
                        return;
                    }
                    //均取当天的最后一秒的时间，然后比较天数
                    if (!(DateUtil.endTimeInDay(vipEndTime) - endTimeToday <= DateUtil.ONE_DAY * vipRenewEmailTemplate.getRemindDay())) {
                        logger.info("vip end time is not in the remind time , customer id {}", customer.getId());
                        return;
                    }

                    //会员没有邮件 
                    if (isEmpty(customer.getEmail())) {
                        logger.info("customer do not has email");
                        return;
                    }

                    //在通知范围内，查看最近有没有发送过，如果已经发送过了，那么也不发送
                    List<TaskExecuteHistory> customerRenewHistoryList = customerTaskService.findCustomerRenewHistory(customer.getId());

                    boolean present = isVipTaskExecuted(currentTimeMillis, vipRenewEmailTemplate, customerRenewHistoryList);

                    //发送历史记录为空，或者在指定时间范围内没有发送过
                    if (isEmpty(customerRenewHistoryList) || !present) {
                        //判断配额是否足够
                        Integer emailCanUsed = getInt(quota.getEmailCanUsed());
                        if (emailCanUsed <= 0) {
                            logger.info("email can used is not enough");
                            return;
                        }

                        try {
                            quota.setEmailCanUsed(emailCanUsed - 1);
                            quota.setEmailUsed(getInt(quota.getEmailUsed()) + 1);
                            commonService.save(quota);
                        } catch (Exception e) {
                            logger.error("e", e);
                            return;
                        }

                        //开始发送
                        try {
                            CustomerEmailClient.getInstance().sendEmail(company.getCompanyConfig().getSendNameInEmail(), customer.getEmail(),
                                    vipRenewEmailTemplate.getTitle(), vipRenewEmailTemplate.getContent(), customer, vipRenewEmailTemplate);

                            customerService.addEmailSendHistory(companyId, true);

                            //添加收件人数
                            marketHistory.setPersonCount(getInt(marketHistory.getPersonCount()) + 1);
                            marketHistory.setEmailCount(getInt(marketHistory.getEmailCount()) + 1);
                        } catch (Exception e) {
                            logger.error("e");
                        }

                        //添加发送日志
                        {
                            TaskExecuteHistory taskExecuteHistory = new TaskExecuteHistory();
                            taskExecuteHistory.setCustomerId(customer.getId());
                            taskExecuteHistory.setTaskType(CUSTOMER_TASK_TYPE_RE_NEW_VIP);
                            taskExecuteHistory.setSortField(new String[]{"createTime"});
                            try {
                                commonService.createObject(taskExecuteHistory);
                            } catch (Exception e) {
                                logger.error("e");
                            }
                        }
                    }
                }));

                //人数大于0的时候处理
                if (marketHistory.getPersonCount() > 0) {
                    logger.info("will save market history {}", marketHistory);
                    commonService.directSave(marketHistory);
                }
            }));
        } catch (Exception e) {
            logger.error("e", e);
        }
    }

    private boolean isVipTaskExecuted(long currentTimeMillis, VipRenewEmailTemplate vipRenewEmailTemplate, List<TaskExecuteHistory> customerRenewHistoryList) {
        boolean present = false;
        if (vipRenewEmailTemplate.getRemindDay() != 0) {
            present = customerRenewHistoryList.stream().filter(p -> currentTimeMillis - p.getCreateTime() < vipRenewEmailTemplate.getRemindDay() * DateUtil.ONE_DAY).findAny().isPresent();
        }else if (vipRenewEmailTemplate.getRemindDay() == 0) {
            //只要在当天有发送记录就不再发送
            present = customerRenewHistoryList.stream().filter(p -> DateUtil.startTimeInDay(currentTimeMillis) < p.getCreateTime() && DateUtil.endTimeInDay(currentTimeMillis) > p.getCreateTime()).findAny().isPresent();
        }
        return present;
    }

    private Company getCompany(Long companyId) {
        Company company = null;

        try {
            company = CompanyService.getInstance().findCompanyById(companyId);
        } catch (Exception e) {
            logger.error("e", e);
        }
        return company;
    }

    private Quota getQuota(Long companyId) {
        Quota quota;
        //查询配额
        try {
            Optional<Quota> quotaOrCreate = customerService.findQuotaOrCreate(companyId);
            if (!quotaOrCreate.isPresent()) {
                return null;
            }

            quota = quotaOrCreate.get();
        } catch (Exception e) {
            //没有找到配额，结束了
            logger.error("e", e);
            return null;
        }
        return quota;
    }

}
